home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / asrc29p.lha / tcpuser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  8.3 KB  |  343 lines

  1. /* User calls to TCP */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "timer.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "internet.h"
  9. #include "tcp.h"
  10. #include "ip.h"
  11. #include "icmp.h"
  12. #include "proc.h"
  13.  
  14. int16 Tcp_window = DEF_WND;
  15.  
  16. struct tcb *open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  17. struct socket *lsocket;   /* Local socket */
  18. struct socket *fsocket;   /* Remote socket */
  19. int mode;                 /* Active/passive/server */
  20. int16 window;             /* Receive window (and send buffer) sizes */
  21. void (*r_upcall)();       /* Function to call when data arrives */
  22. void (*t_upcall)();       /* Function to call when ok to send more data */
  23. void (*s_upcall)();       /* Function to call when connection state changes */
  24. int tos;
  25. int user;                 /* User linkage area */
  26. {
  27.    struct connection conn;
  28.    register struct tcb *tcb;
  29.  
  30.    if(lsocket == NULLSOCK) {
  31.       Net_error = INVALID;
  32.       return NULLTCB;
  33.    }
  34.    conn.local.address = lsocket->address;
  35.    conn.local.port = lsocket->port;
  36.    if(fsocket != NULLSOCK) {
  37.       conn.remote.address = fsocket->address;
  38.       conn.remote.port = fsocket->port;
  39.    } else {
  40.       conn.remote.address = 0;
  41.       conn.remote.port = 0;
  42.    }
  43.    if((tcb = lookup_tcb(&conn)) == NULLTCB) {
  44.       if((tcb = create_tcb(&conn)) == NULLTCB) {
  45.          Net_error = NO_MEM;
  46.          return NULLTCB;
  47.       }
  48.    } else if(tcb->state != TCP_LISTEN) {
  49.       Net_error = CON_EXISTS;
  50.       return NULLTCB;
  51.    }
  52.    tcb->user = user;
  53.    if(window != 0)
  54.       tcb->window = tcb->rcv.wnd = window;
  55.    else
  56.       tcb->window = tcb->rcv.wnd = Tcp_window;
  57.    tcb->snd.wnd = 1;   /* Allow space for sending a SYN */
  58.    tcb->r_upcall = r_upcall;
  59.    tcb->t_upcall = t_upcall;
  60.    tcb->s_upcall = s_upcall;
  61.    tcb->tos = tos;
  62.    switch(mode) {
  63.    case TCP_SERVER:
  64.       tcb->flags.clone = 1;
  65.    case TCP_PASSIVE:   /* Note fall-thru */
  66.       setstate(tcb,TCP_LISTEN);
  67.       break;
  68.    case TCP_ACTIVE:
  69.       /* Send SYN, go into TCP_SYN_SENT state */
  70.       tcb->flags.active = 1;
  71.       send_syn(tcb);
  72.       setstate(tcb,TCP_SYN_SENT);
  73.       tcp_output(tcb);
  74.       break;
  75.    }
  76.    return tcb;
  77. }
  78.  
  79. /* User send routine */
  80. int send_tcp(tcb,bp)
  81. register struct tcb *tcb;
  82. struct mbuf *bp;
  83. {
  84.    int16 cnt;
  85.  
  86.    if(tcb == NULLTCB || bp == NULLBUF) {
  87.       free_p(bp);
  88.       Net_error = INVALID;
  89.       return -1;
  90.    }
  91.    cnt = len_p(bp);
  92.    switch(tcb->state) {
  93.    case TCP_CLOSED:
  94.       free_p(bp);
  95.       Net_error = NO_CONN;
  96.       return -1;
  97.    case TCP_LISTEN:
  98.       if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0) {
  99.          /* Save data for later */
  100.          append(&tcb->sndq,bp);
  101.          tcb->sndcnt += cnt;
  102.          break;
  103.       }      
  104.       /* Change state from passive to active */
  105.       tcb->flags.active = 1;
  106.       send_syn(tcb);
  107.       setstate(tcb,TCP_SYN_SENT);   /* Note fall-thru */
  108.    case TCP_SYN_SENT:
  109.    case TCP_SYN_RECEIVED:
  110.    case TCP_ESTABLISHED:
  111.    case TCP_CLOSE_WAIT:
  112.       append(&tcb->sndq,bp);
  113.       tcb->sndcnt += cnt;
  114.       tcp_output(tcb);
  115.       break;
  116.    case TCP_FINWAIT1:
  117.    case TCP_FINWAIT2:
  118.    case TCP_CLOSING:
  119.    case TCP_LAST_ACK:
  120.    case TCP_TIME_WAIT:
  121.       free_p(bp);
  122.       Net_error = CON_CLOS;
  123.       return -1;
  124.    }
  125.    return (int)cnt;
  126. }
  127.  
  128. /* User receive routine */
  129. int recv_tcp(tcb,bpp,cnt)
  130. register struct tcb *tcb;
  131. struct mbuf **bpp;
  132. int16 cnt;
  133. {
  134.    if(tcb == NULLTCB || bpp == (struct mbuf **)NULL) {
  135.       Net_error = INVALID;
  136.       return -1;
  137.    }
  138.    if(tcb->rcvcnt == 0) {
  139.       /* If there's nothing on the queue, our action depends on what state
  140.        * we're in (i.e., whether or not we're expecting any more data).
  141.        * If no more data is expected, then simply return 0; this is
  142.        * interpreted as "end of file". Otherwise return -1. */
  143.       switch(tcb->state){
  144.       case TCP_LISTEN:
  145.       case TCP_SYN_SENT:
  146.       case TCP_SYN_RECEIVED:
  147.       case TCP_ESTABLISHED:
  148.       case TCP_FINWAIT1:
  149.       case TCP_FINWAIT2:
  150.          Net_error = WOULDBLK;
  151.          return -1;
  152.       case TCP_CLOSED:
  153.       case TCP_CLOSE_WAIT:
  154.       case TCP_CLOSING:
  155.       case TCP_LAST_ACK:
  156.       case TCP_TIME_WAIT:
  157.          *bpp = NULLBUF;
  158.          return 0;
  159.       }
  160.    }
  161.    /* cnt == 0 means "I want it all" */
  162.    if(cnt == 0)
  163.       cnt = tcb->rcvcnt;
  164.    /* See if the user can take all of it */
  165.    if(tcb->rcvcnt <= cnt) {
  166.       cnt = tcb->rcvcnt;
  167.       *bpp = tcb->rcvq;
  168.       tcb->rcvq = NULLBUF;
  169.    } else {
  170.       if((*bpp = alloc_mbuf(cnt)) == NULLBUF) {
  171.          Net_error = NO_MEM;
  172.          return -1;
  173.       }
  174.       pullup(&tcb->rcvq,(*bpp)->data,cnt);
  175.       (*bpp)->cnt = cnt;
  176.    }
  177.    tcb->rcvcnt -= cnt;
  178.    tcb->rcv.wnd += cnt;
  179.    /* Do a window update if it was closed */
  180.    if(cnt == tcb->rcv.wnd) {
  181.       tcb->flags.force = 1;
  182.       tcp_output(tcb);
  183.    }
  184.    return (int)cnt;
  185. }
  186.  
  187. /* This really means "I have no more data to send". It only closes the
  188.  * connection in one direction, and we can continue to receive data
  189.  * indefinitely.  */
  190. int close_tcp(tcb)
  191. register struct tcb *tcb;
  192. {
  193.    if(tcb == NULLTCB) {
  194.       Net_error = INVALID;
  195.       return -1;
  196.    }
  197.    switch(tcb->state) {
  198.    case TCP_CLOSED:
  199.       return 0;   /* Unlikely */
  200.    case TCP_LISTEN:
  201.    case TCP_SYN_SENT:
  202.       close_self(tcb,NORMAL);
  203.       return 0;
  204.    case TCP_SYN_RECEIVED:
  205.    case TCP_ESTABLISHED:
  206.       tcb->sndcnt++;
  207.       tcb->snd.nxt++;
  208.       setstate(tcb,TCP_FINWAIT1);
  209.       tcp_output(tcb);
  210.       return 0;
  211.    case TCP_CLOSE_WAIT:
  212.       tcb->sndcnt++;
  213.       tcb->snd.nxt++;
  214.       setstate(tcb,TCP_LAST_ACK);
  215.       tcp_output(tcb);
  216.       return 0;
  217.    case TCP_FINWAIT1:
  218.    case TCP_FINWAIT2:
  219.    case TCP_CLOSING:
  220.    case TCP_LAST_ACK:
  221.    case TCP_TIME_WAIT:
  222.       Net_error = CON_CLOS;
  223.       return -1;
  224.    }
  225.    return -1;   /* "Can't happen" */
  226. }
  227.  
  228. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  229.  * not in the TCP_CLOSED state. This function should normally be called by the
  230.  * user only in response to a state change upcall to TCP_CLOSED state. */
  231. int del_tcp(tcb)
  232. register struct tcb *tcb;
  233. {
  234.    struct reseq *rp,*rp1;
  235.  
  236.    if(tcb == NULLTCB) {
  237.       Net_error = INVALID;
  238.       return -1;
  239.    }
  240.    unlink_tcb(tcb);
  241.    stop_timer(&tcb->timer);
  242.    for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1) {
  243.       rp1 = rp->next;
  244.       free_p(rp->bp);
  245.       free((char *)rp);
  246.    }
  247.    tcb->reseq = NULLRESEQ;
  248.    free_p(tcb->rcvq);
  249.    free_p(tcb->sndq);
  250.    free((char *)tcb);
  251.    return 0;
  252. }
  253.  
  254. /* Return 1 if arg is a valid TCB, 0 otherwise */
  255. int tcpval(tcb)
  256. struct tcb *tcb;
  257. {
  258.    register int i;
  259.    register struct tcb *tcb1;
  260.  
  261.    if(tcb == NULLTCB)
  262.       return 0;   /* Null pointer can't be valid */
  263.    for(i=0;i<NTCB;i++) {
  264.       for(tcb1=Tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next) {
  265.          if(tcb1 == tcb)
  266.             return 1;
  267.       }
  268.    }
  269.    return 0;
  270. }
  271.  
  272. /* Kick a particular TCP connection */
  273. int kick_tcp(tcb)
  274. register struct tcb *tcb;
  275. {
  276.    if(!tcpval(tcb))
  277.       return -1;
  278.    tcp_timeout(tcb);
  279.    return 0;
  280. }
  281.  
  282. /* Kick all TCP connections to specified address; return number kicked */
  283. int kick(addr)
  284. int32 addr;
  285. {
  286.    register int i;
  287.    register struct tcb *tcb;
  288.    int cnt = 0;
  289.  
  290.    for(i=0;i<NTCB;i++) {
  291.       for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next) {
  292.          if(tcb->conn.remote.address == addr){
  293.             kick_tcp(tcb);
  294.             cnt++;
  295.          }
  296.       }
  297.    }
  298.    return cnt;
  299. }
  300.  
  301. /* Clear all TCP connections */
  302. void reset_all()
  303. {
  304.    register int i;
  305.    register struct tcb *tcb;
  306.  
  307.    for(i=0;i<NTCB;i++) 
  308.       for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next) 
  309.          reset_tcp(tcb);
  310.  
  311.    pause(1000/MSPTICK);
  312.    /* pwait(NULL);   Let the RSTs go forth */
  313. }
  314.  
  315. void reset_tcp(tcb)
  316. register struct tcb *tcb;
  317. {
  318.    struct tcp fakeseg;
  319.    struct ip fakeip;
  320.  
  321.    if(tcb == NULLTCB)
  322.       return;
  323.    if(tcb->state != TCP_LISTEN) {
  324.       /* Compose a fake segment with just enough
  325.          info to generate the correct RST reply */
  326.       memset((char *)&fakeseg,0,sizeof(fakeseg));
  327.       memset((char *)&fakeip,0,sizeof(fakeip));
  328.       fakeseg.flags.rst = 0;
  329.       fakeseg.dest = tcb->conn.local.port;
  330.       fakeseg.source = tcb->conn.remote.port;
  331.       fakeseg.flags.ack = 1;
  332.       /* Here we try to pick a sequence number with the greatest likelihood
  333.        * of being in his receive window.        */
  334.       fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  335.       fakeip.dest = tcb->conn.local.address;
  336.       fakeip.source = tcb->conn.remote.address;
  337.       fakeip.tos = tcb->tos;
  338.       reset(&fakeip,&fakeseg);
  339.    }
  340.    close_self(tcb,RESET);
  341. }
  342.  
  343.